package com.tbynet.jwp.framework.core;

import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Supplier;

/**
 * 通用服务实现基类 - 支持复合主键和自动表名获取
 *
 * 核心特性：
 * 1. 自动类型推断：通过泛型自动获取实体类类型
 * 2. 表信息缓存：避免重复反射获取表信息
 * 3. 复合主键支持：完整支持复合主键的CRUD操作
 * 4. 统一异常处理：所有操作都包含完整的异常处理和日志记录
 * 5. 性能监控：内置方法执行时间监控和统计
 *
 * 使用说明：
 * <pre>{@code
 * // 1. 基础使用
 * public class UserService extends JwpServiceProvider<User> {
 *     // 自动获得所有基础CRUD能力
 * }
 *
 * // 2. 自定义搜索逻辑
 * public class UserService extends JwpServiceProvider<User> {
 *     @Override
 *     protected String buildSearchWhereSql(String keyword, List<Object> params) {
 *         if (StrKit.notBlank(keyword)) {
 *             params.add("%" + keyword + "%");
 *             params.add("%" + keyword + "%");
 *             params.add("%" + keyword + "%");
 *             return " WHERE (username LIKE ? OR email LIKE ? OR real_name LIKE ?)";
 *         }
 *         return " WHERE 1=1";
 *     }
 *
 *     @Override
 *     protected String getDefaultOrderBy() {
 *         return "create_time DESC, id DESC";
 *     }
 * }
 * }</pre>
 *
 * @param <T> 实体类型，必须继承自JFinal的Model
 * @author 佰亿互联
 * @version 3.0
 * @since 2025-11-04
 */
public abstract class _JwpServiceProvider<T extends JwpModel<T>> implements _JwpService<T> {

    /** 日志记录器 */
    protected final Log log = Log.getLog(this.getClass());

    // ========== 缓存字段 ==========
    private volatile Table tableInfo;
    private volatile String[] primaryKeyArray;
    private final Class<T> modelClass;
    private volatile T daoInstance;

    // ========== 构造函数 ==========

    /**
     * 构造函数 - 通过反射获取泛型类型
     *
     * @throws IllegalStateException 当无法确定泛型类型时抛出
     */
    @SuppressWarnings("unchecked")
    public _JwpServiceProvider() {
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            if (actualTypeArguments.length > 0 && actualTypeArguments[0] instanceof Class) {
                this.modelClass = (Class<T>) actualTypeArguments[0];
                log.debug("成功推断实体类类型: %s", modelClass.getName());
                return;
            }
        }
        throw new IllegalStateException("无法确定泛型类型，请确保子类正确指定了泛型参数");
    }

    // ========== 核心工具方法 ==========

    /**
     * 获取DAO实例（线程安全缓存）
     *
     * @return DAO实例，不会返回null
     * @throws RuntimeException 当获取DAO实例失败时抛出
     */
    protected T getDao() {
        if (daoInstance == null) {
            synchronized (this) {
                if (daoInstance == null) {
                    try {
                        T modelInstance = modelClass.getDeclaredConstructor().newInstance();
                        Method daoMethod = modelClass.getMethod("dao");
                        daoInstance = (T) daoMethod.invoke(modelInstance);
                        log.debug("成功初始化DAO实例: %s", modelClass.getName());
                    } catch (Exception e) {
                        String errorMsg = "获取DAO实例失败: " + modelClass.getName();
                        log.error(errorMsg, e);
                        throw new RuntimeException(errorMsg, e);
                    }
                }
            }
        }
        return daoInstance;
    }

    /**
     * 获取表信息（线程安全缓存）
     *
     * @return 表信息对象，不会返回null
     * @throws IllegalStateException 当无法获取表信息时抛出
     */
    protected Table getTableInfo() {
        if (tableInfo == null) {
            synchronized (this) {
                if (tableInfo == null) {
                    tableInfo = TableMapping.me().getTable(modelClass);
                    if (tableInfo == null) {
                        throw new IllegalStateException("无法获取表信息: " + modelClass.getName());
                    }
                    log.debug("成功加载表信息: %s -> %s", modelClass.getName(), tableInfo.getName());
                }
            }
        }
        return tableInfo;
    }

    /**
     * 获取数据库表名
     *
     * @return 数据库表名，不会返回null
     */
    protected String getTableName() {
        return getTableInfo().getName();
    }

    /**
     * 获取主键字段数组（支持复合主键）
     *
     * @return 主键字段名数组，至少包含一个元素
     */
    protected String[] getPrimaryKeyArray() {
        if (primaryKeyArray == null) {
            synchronized (this) {
                if (primaryKeyArray == null) {
                    Table table = getTableInfo();
                    primaryKeyArray = table.getPrimaryKey();
                    if (primaryKeyArray == null || primaryKeyArray.length == 0) {
                        log.warn("表 %s 未定义主键，使用默认主键 'id'", getTableName());
                        primaryKeyArray = new String[]{"id"};
                    }
                    log.debug("表 %s 主键字段: %s", getTableName(), Arrays.toString(primaryKeyArray));
                }
            }
        }
        return primaryKeyArray;
    }

    /**
     * 检查是否为复合主键
     *
     * @return 主键字段数量大于1时返回true
     */
    protected boolean isCompositePrimaryKey() {
        return getPrimaryKeyArray().length > 1;
    }

    // ========== 基础CRUD操作实现 ==========

    @Override
    public T getById(Object id) {
        return executeWithResultLogging("getById", () -> {
            validateNotNull(id, "主键参数不能为空");
            return getDao().findById(id);
        }, id);
    }

    @Override
    public T getByIds(Object... ids) {
        return executeWithResultLogging("getByIds", () -> {
            validatePrimaryKeys(ids);
            return getDao().findByIds(ids);
        }, (Object) ids);
    }

    @Override
    public boolean save(T entity) {
        return executeWithBooleanLogging("save", () -> {
            validateNotNull(entity, "实体对象不能为空");
            return entity.save();
        }, getEntityIds(entity));
    }

    @Override
    public boolean update(T entity) {
        return executeWithBooleanLogging("update", () -> {
            validateNotNull(entity, "实体对象不能为空");
            validateEntityHasPrimaryKey(entity);
            return entity.update();
        }, getEntityIds(entity));
    }

    @Override
    public boolean deleteById(Object id) {
        return executeWithBooleanLogging("deleteById", () -> {
            validateNotNull(id, "主键参数不能为空");
            return getDao().deleteById(id);
        }, id);
    }

    @Override
    public boolean deleteByIds(Object... ids) {
        return executeWithBooleanLogging("deleteByIds", () -> {
            validatePrimaryKeys(ids);
            return getDao().deleteByIds(ids);
        }, (Object) ids);
    }

    @Override
    public List<T> getByIdList(List<Object> ids) {
        return executeWithResultLogging("getByIdList", () -> {
            if (ids == null || ids.isEmpty()) {
                return Collections.emptyList();
            }
            if (isCompositePrimaryKey()) {
                log.warn("复合主键表不支持批量ID查询: %s", getTableName());
                return Collections.emptyList();
            }
            String sql = buildInQuerySql(ids);
            return getDao().find(sql, ids.toArray());
        }, ids.size());
    }

    // ========== 查询和搜索功能实现 ==========

    @Override
    public Page<T> search(int pageNumber, int pageSize, String keyword) {
        return executeWithResultLogging("search", () -> {
            SearchContext context = new SearchContext(pageNumber, pageSize);
            List<Object> params = new ArrayList<>();
            String whereSql = buildSearchWhereSql(keyword, params);
            String sql = buildPageSql(whereSql, getDefaultOrderBy());
            return getDao().paginate(context.pageNumber, context.pageSize, "SELECT *", sql, params.toArray());
        }, keyword);
    }

    @Override
    public Page<T> advancedSearch(int pageNumber, int pageSize, Map<String, Object> conditions) {
        return executeWithResultLogging("advancedSearch", () -> {
            SearchContext context = new SearchContext(pageNumber, pageSize);
            List<Object> params = new ArrayList<>();
            String whereSql = buildAdvancedSearchWhereSql(conditions, params);
            String sql = buildPageSql(whereSql, getDefaultOrderBy());
            return getDao().paginate(context.pageNumber, context.pageSize, "SELECT *", sql, params.toArray());
        }, conditions != null ? conditions.size() : 0);
    }

    @Override
    public List<T> getAll() {
        return executeWithResultLogging("getAll", () -> {
            String sql = "SELECT * FROM " + getTableName() + " ORDER BY " + getDefaultOrderBy();
            return getDao().find(sql);
        });
    }

    @Override
    public List<T> find(String sql, Object... params) {
        return executeWithResultLogging("find", () -> {
            validateNotBlank(sql, "SQL语句不能为空");
            return getDao().find(sql, params);
        }, getShortSql(sql), params.length);
    }

    @Override
    public T findOne(Map<String, Object> conditions) {
        return executeWithResultLogging("findOne", () -> {
            if (conditions == null || conditions.isEmpty()) {
                return findFirst();
            }
            List<Object> params = new ArrayList<>();
            String whereSql = buildConditionWhereSql(conditions, params);
            String sql = "SELECT * FROM " + getTableName() + whereSql + " LIMIT 1";
            return getDao().findFirst(sql, params.toArray());
        }, conditions != null ? conditions.size() : 0);
    }

    @Override
    public List<T> findList(Map<String, Object> conditions) {
        return findList(conditions, null);
    }

    @Override
    public List<T> findList(Map<String, Object> conditions, String orderBy) {
        return executeWithResultLogging("findList", () -> {
            List<Object> params = new ArrayList<>();
            String whereSql = buildConditionWhereSql(conditions, params);
            String orderByClause = " ORDER BY " + (orderBy != null ? orderBy : getDefaultOrderBy());
            String sql = "SELECT * FROM " + getTableName() + whereSql + orderByClause;
            return getDao().find(sql, params.toArray());
        }, conditions != null ? conditions.size() : 0, orderBy);
    }

    // ========== 存在性检查和统计实现 ==========

    @Override
    public boolean existsById(Object id) {
        return executeWithBooleanLogging("existsById", () -> {
            validateNotNull(id, "主键参数不能为空");
            String sql = buildExistsSql(buildPrimaryKeyCondition());
            Long exists = Db.queryLong(sql, id);
            return exists != null && exists == 1;
        }, id);
    }

    @Override
    public boolean existsByIds(Object... ids) {
        return executeWithBooleanLogging("existsByIds", () -> {
            validatePrimaryKeys(ids);
            String sql = buildExistsSql(buildPrimaryKeyCondition());
            Long exists = Db.queryLong(sql, ids);
            return exists != null && exists == 1;
        }, (Object) ids);
    }

    @Override
    public boolean existsByField(String field, Object value) {
        return executeWithBooleanLogging("existsByField", () -> {
            validateNotBlank(field, "字段名不能为空");
            validateNotNull(value, "字段值不能为空");
            String sql = buildExistsSql(field + " = ?");
            Long exists = Db.queryLong(sql, value);
            return exists != null && exists == 1;
        }, field, value);
    }

    @Override
    public long getCount() {
        return executeWithResultLogging("getCount", () -> {
            String sql = "SELECT COUNT(*) FROM " + getTableName();
            Long count = Db.queryLong(sql);
            return count != null ? count : 0;
        });
    }

    @Override
    public long getCountByConditions(Map<String, Object> conditions) {
        return executeWithResultLogging("getCountByConditions", () -> {
            if (conditions == null || conditions.isEmpty()) {
                return getCount();
            }
            List<Object> params = new ArrayList<>();
            String whereSql = buildConditionWhereSql(conditions, params);
            String sql = "SELECT COUNT(*) FROM " + getTableName() + whereSql;
            Long count = Db.queryLong(sql, params.toArray());
            return count != null ? count : 0;
        }, conditions.size());
    }

    @Override
    public boolean isFieldUnique(String field, Object value, Object... excludeIds) {
        return executeWithBooleanLogging("isFieldUnique", () -> {
            validateNotBlank(field, "字段名不能为空");
            validateNotNull(value, "字段值不能为空");

            StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM ")
                    .append(getTableName())
                    .append(" WHERE ")
                    .append(field)
                    .append(" = ?");

            List<Object> params = new ArrayList<>();
            params.add(value);

            // 排除指定记录
            if (excludeIds != null && excludeIds.length > 0) {
                sql.append(" AND NOT (").append(buildPrimaryKeyCondition()).append(")");
                Collections.addAll(params, excludeIds);
            }

            Long count = Db.queryLong(sql.toString(), params.toArray());
            return count != null && count == 0;
        }, field, value, excludeIds);
    }

    @Override
    public T findFirst() {
        return executeWithResultLogging("findFirst", () -> {
            String sql = "SELECT * FROM " + getTableName() + " ORDER BY " + getDefaultOrderBy() + " LIMIT 1";
            return getDao().findFirst(sql);
        });
    }

    @Override
    public T findLast() {
        return executeWithResultLogging("findLast", () -> {
            String defaultOrderBy = getDefaultOrderBy();
            String reversedOrderBy = reverseOrderBy(defaultOrderBy);
            String sql = "SELECT * FROM " + getTableName() + " ORDER BY " + reversedOrderBy + " LIMIT 1";
            return getDao().findFirst(sql);
        });
    }

    @Override
    public T getBasicInfoById(Object id) {
        return executeWithResultLogging("getBasicInfoById", () -> {
            validateNotNull(id, "主键参数不能为空");
            String fields = getBasicFields();
            String sql = "SELECT " + fields + " FROM " + getTableName() + " WHERE " + buildPrimaryKeyCondition();
            return getDao().findFirst(sql, id);
        }, id);
    }

    @Override
    public T getBasicInfoByIds(Object... ids) {
        return executeWithResultLogging("getBasicInfoByIds", () -> {
            validatePrimaryKeys(ids);
            String fields = getBasicFields();
            String sql = "SELECT " + fields + " FROM " + getTableName() + " WHERE " + buildPrimaryKeyCondition();
            return getDao().findFirst(sql, ids);
        }, (Object) ids);
    }

    // ========== 可重写的模板方法 ==========

    /**
     * 构建搜索条件的WHERE子句
     *
     * 子类必须重写此方法来实现具体的搜索逻辑
     *
     * @param keyword 搜索关键词，可能为null或空
     * @param params 参数列表，用于收集SQL参数
     * @return WHERE子句，包含" WHERE "前缀
     *
     * 使用示例：
     * <pre>{@code
     * @Override
     * protected String buildSearchWhereSql(String keyword, List<Object> params) {
     *     if (StrKit.notBlank(keyword)) {
     *         params.add("%" + keyword + "%");
     *         params.add("%" + keyword + "%");
     *         params.add("%" + keyword + "%");
     *         return " WHERE (username LIKE ? OR email LIKE ? OR real_name LIKE ?)";
     *     }
     *     return " WHERE 1=1";
     * }
     * }</pre>
     */
    protected abstract String buildSearchWhereSql(String keyword, List<Object> params);

    /**
     * 构建高级搜索条件的WHERE子句
     *
     * @param conditions 搜索条件Map
     * @param params 参数列表，用于收集SQL参数
     * @return WHERE子句，包含" WHERE "前缀
     */
    protected String buildAdvancedSearchWhereSql(Map<String, Object> conditions, List<Object> params) {
        if (conditions == null || conditions.isEmpty()) {
            return " WHERE 1=1";
        }

        StringBuilder whereSql = new StringBuilder(" WHERE 1=1");
        for (Map.Entry<String, Object> entry : conditions.entrySet()) {
            String field = entry.getKey();
            Object value = entry.getValue();

            if (value == null) continue;

            // 处理特殊操作符
            if (field.contains(":")) {
                String[] parts = field.split(":", 2);
                String actualField = parts[0];
                String operator = parts[1].toLowerCase();

                switch (operator) {
                    case "like":
                        whereSql.append(" AND ").append(actualField).append(" LIKE ?");
                        params.add("%" + value + "%");
                        break;
                    case "gt":
                    case "ge":
                    case "lt":
                    case "le":
                    case "ne":
                        whereSql.append(" AND ").append(actualField).append(" ").append(getOperatorSymbol(operator)).append(" ?");
                        params.add(value);
                        break;
                    default:
                        whereSql.append(" AND ").append(actualField).append(" = ?");
                        params.add(value);
                }
            } else {
                // 默认等值查询
                whereSql.append(" AND ").append(field).append(" = ?");
                params.add(value);
            }
        }
        return whereSql.toString();
    }

    /**
     * 获取默认排序字段
     *
     * @return 排序字段，如 "create_time DESC"
     */
    protected String getDefaultOrderBy() {
        String[] primaryKeys = getPrimaryKeyArray();
        if (primaryKeys.length == 1) {
            return primaryKeys[0] + " DESC";
        }
        return String.join(" DESC, ", primaryKeys) + " DESC";
    }

    /**
     * 获取基本信息字段
     *
     * @return 字段列表，逗号分隔
     */
    protected String getBasicFields() {
        return "*"; // 默认返回所有字段，子类可重写
    }

    // ========== 私有工具方法 ==========

    /**
     * 带日志记录的执行模板方法
     */
    protected <R> R executeWithResultLogging(String operation, Supplier<R> operationSupplier, Object... logParams) {
        long startTime = System.currentTimeMillis();
        try {
            R result = operationSupplier.get();
            long cost = System.currentTimeMillis() - startTime;
            if (cost > JwpConstants.SLOW_METHOD_THRESHOLD) {
                log.warn("%s操作较慢, 表: %s, 参数: %s, 耗时: %sms",
                        operation, getTableName(), Arrays.toString(logParams), cost);
            } else {
                log.debug("%s操作完成, 表: %s, 参数: %s, 耗时: %sms",
                        operation, getTableName(), Arrays.toString(logParams), cost);
            }
            return result;
        } catch (Exception e) {
            log.error("%s操作异常, 表: %s, 参数: %s",
                    operation, getTableName(), Arrays.toString(logParams), e);
            return null;
        }
    }

    protected boolean executeWithBooleanLogging(String operation, Supplier<Boolean> operationSupplier, Object... logParams) {
        long startTime = System.currentTimeMillis();
        try {
            boolean result = operationSupplier.get();
            long cost = System.currentTimeMillis() - startTime;
            if (cost > JwpConstants.SLOW_METHOD_THRESHOLD) {
                log.warn("%s操作较慢, 表: %s, 参数: %s, 结果: %s, 耗时: %sms",
                        operation, getTableName(), Arrays.toString(logParams), result, cost);
            } else {
                log.debug("%s操作完成, 表: %s, 参数: %s, 结果: %s, 耗时: %sms",
                        operation, getTableName(), Arrays.toString(logParams), result, cost);
            }
            return result;
        } catch (Exception e) {
            log.error("%s操作异常, 表: %s, 参数: %s",
                    operation, getTableName(), Arrays.toString(logParams), e);
            return false;
        }
    }

    /**
     * 参数验证方法
     */
    protected void validateNotNull(Object obj, String message) {
        if (obj == null) {
            throw new IllegalArgumentException(message);
        }
    }

    protected void validateNotBlank(String str, String message) {
        if (StrKit.isBlank(str)) {
            throw new IllegalArgumentException(message);
        }
    }

    protected void validatePrimaryKeys(Object[] ids) {
        if (ids == null || ids.length == 0) {
            throw new IllegalArgumentException("主键参数不能为空");
        }
        String[] primaryKeys = getPrimaryKeyArray();
        if (ids.length != primaryKeys.length) {
            throw new IllegalArgumentException(
                    String.format("主键数量不匹配，期望: %d，实际: %d", primaryKeys.length, ids.length));
        }
    }

    protected void validateEntityHasPrimaryKey(T entity) {
        Object[] entityIds = getEntityIds(entity);
        if (entityIds.length == 0 || Arrays.stream(entityIds).allMatch(Objects::isNull)) {
            throw new IllegalArgumentException("实体缺少主键值: " + getTableName());
        }
    }

    /**
     * SQL构建工具方法
     */
    private String buildExistsSql(String condition) {
        return "SELECT EXISTS(SELECT 1 FROM " + getTableName() + " WHERE " + condition + " LIMIT 1)";
    }

    protected String buildPageSql(String whereSql, String orderBy) {
        return "FROM " + getTableName() + whereSql + " ORDER BY " + orderBy;
    }

    private String buildPrimaryKeyCondition() {
        String[] primaryKeys = getPrimaryKeyArray();
        if (primaryKeys.length == 1) {
            return primaryKeys[0] + " = ?";
        }
        StringBuilder condition = new StringBuilder();
        for (int i = 0; i < primaryKeys.length; i++) {
            if (i > 0) condition.append(" AND ");
            condition.append(primaryKeys[i]).append(" = ?");
        }
        return condition.toString();
    }

    private String buildInQuerySql(List<Object> ids) {
        String primaryKey = getPrimaryKeyArray()[0];
        String placeholders = String.join(",", Collections.nCopies(ids.size(), "?"));
        return "SELECT * FROM " + getTableName() + " WHERE " + primaryKey + " IN (" + placeholders + ")";
    }

    private String buildConditionWhereSql(Map<String, Object> conditions, List<Object> params) {
        if (conditions == null || conditions.isEmpty()) {
            return " WHERE 1=1";
        }
        StringBuilder whereSql = new StringBuilder(" WHERE 1=1");
        for (Map.Entry<String, Object> entry : conditions.entrySet()) {
            if (entry.getValue() != null) {
                whereSql.append(" AND ").append(entry.getKey()).append(" = ?");
                params.add(entry.getValue());
            }
        }
        return whereSql.toString();
    }

    private String getOperatorSymbol(String operator) {
        switch (operator) {
            case "gt": return ">";
            case "ge": return ">=";
            case "lt": return "<";
            case "le": return "<=";
            case "ne": return "!=";
            default: return "=";
        }
    }

    private String reverseOrderBy(String orderBy) {
        // 简单实现：将 DESC 和 ASC 互换
        return orderBy.replace(" DESC", " ASC").replace(" ASC", " DESC");
    }

    private Object[] getEntityIds(T entity) {
        String[] primaryKeys = getPrimaryKeyArray();
        Object[] ids = new Object[primaryKeys.length];
        for (int i = 0; i < primaryKeys.length; i++) {
            ids[i] = entity.get(primaryKeys[i]);
        }
        return ids;
    }

    private String getShortSql(String sql) {
        return StrKit.isBlank(sql) ? "" :
                (sql.length() > 100 ? sql.substring(0, 100) + "..." : sql);
    }

    // ========== 内部辅助类 ==========

    /**
     * 搜索上下文 - 封装分页参数处理
     */
    private static class SearchContext {
        final int pageNumber;
        final int pageSize;

        SearchContext(int pageNumber, int pageSize) {
            this.pageNumber = Math.max(1, pageNumber);
            this.pageSize = validatePageSize(pageSize);
        }

        private int validatePageSize(int pageSize) {
            if (pageSize < 1) return JwpConstants.DEFAULT_PAGE_SIZE;
            return Math.min(pageSize, JwpConstants.MAX_PAGE_SIZE);
        }
    }
}